﻿using DevelopTool.Bll.DbBlls;
using DevelopTool.Common;
using DevelopTool.Forms.BaseForms;
using DevelopTool.Forms.TextEditorForms;
using DevelopTool.Model;
using DevelopTool.Model.DbModels;
using DevelopTool.OffLine.Bll;
using DevelopTool.OffLine.Model;
using ICSharpCode.TextEditor;
using Sunny.UI;
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;

namespace DevelopTool.OffLine.Forms
{
    /// <summary>
    /// 批量离线
    /// </summary>
    public partial class BatchOfflineDataForm : BaseUIPage
    {
        /// <summary>
        /// 连接信息
        /// </summary>
        private DbInfo dbInfo;


        /// <summary>
        /// 批量离线业务操作类
        /// </summary>
        private BatchOfflineDataBll batchOfflineDataBll;


        /// <summary>
        /// 编辑器对象
        /// </summary>
        private TextEditorControl textEditorControl;


        /// <summary>
        /// 窗体加载完成标记
        /// </summary>
        //private bool isLoaded = false;


        /// <summary>
        /// 检测任务状态的计时器
        /// </summary>
        private Timer timerCheck;


        /// <summary>
        /// 任务报告数据
        /// </summary>
        private DataTable taskReportTable;

        /// <summary>
        /// 总任务开始时间
        /// </summary>
        private DateTime startTime;

        /// <summary>
        /// 总任务执行完成数量
        /// </summary>
        private int executedNum;

        /// <summary>
        /// 总任务数量
        /// </summary>
        private int taskTotalNum;

        /// <summary>
        /// 总任务运行状态，0=未运行，1=正在运行，2=暂停，3=取消
        /// </summary>
        private int status = 0;


        #region 当前任务参数

        /// <summary>
        /// 数据库实例名
        /// </summary>
        private string taskDataBaseName = "";

        /// <summary>
        /// 任务分块数量（每页数据条数）
        /// </summary>
        private int taskPageSize = 10000;

        /// <summary>
        /// 任务使用的线程数量
        /// </summary>
        private int taskThreadNum = 2;

        /// <summary>
        /// 任务异常等待时间
        /// </summary>
        private int taskExWaitTime = 60;

        /// <summary>
        /// 任务异常尝试次数
        /// </summary>
        private int taskExTryNum = 2;

        /// <summary>
        /// 当前任务参数对象
        /// </summary>
        private OffLineTaskParam currentTaskParam;

        #endregion


        /// <summary>
        /// DataGridView列信息集合
        /// </summary>
        private List<DataGridColumn> dataGridColumns = new List<DataGridColumn>()
              {
                { new DataGridColumn("TaskName"){ColumnText="任务名称",Width=300}},
                { new DataGridColumn("TaskStartTime"){ColumnText="开始时间",Width=150}},
                { new DataGridColumn("TaskCompleteTime"){ColumnText="完成时间",Width=150}},
                { new DataGridColumn("TaskUsageTime"){ColumnText="用时(秒)",Width=100}},
                { new DataGridColumn("TaskCompleteType"){ColumnText="状态",Width=70}},
                { new DataGridColumn("TaskTotalRowCount"){ColumnText="总行数",Width=100}},
                { new DataGridColumn("TaskExceptionCount"){ColumnText="异常次数",Width=90}}
              };

        public BatchOfflineDataForm()
        {
            InitializeComponent();
        }

        private void BatchOfflineDataForm_Load(object sender, EventArgs e)
        {
            CheckForIllegalCrossThreadCalls = false;

            //初始化代码编辑器窗体，并加载到窗口
            TextEditorForm textEditorForm = new TextEditorForm(new TextEditorFormShowParam()
            {
                ContentType = "SQL",
                EnabledBtnOpen = false,
                SectionName = GetType().Name
            }, out textEditorControl);
            TabControlHelper.AddFormToControl(uiSplitContainer1.Panel1, textEditorForm);


            //数据库连接选择控件
            this.dbinfoSelectCombo.InitDbinfoComboTreeViewData();


            //初始化任务报告DataTable
            taskReportTable = new DataTable("TaskResult");
            taskReportTable.Columns.Add("TaskName", typeof(string));
            taskReportTable.Columns.Add("TaskStartTime", typeof(DateTime));
            taskReportTable.Columns.Add("TaskCompleteTime", typeof(DateTime));
            taskReportTable.Columns.Add("TaskUsageTime", typeof(double));
            taskReportTable.Columns.Add("TaskTotalRowCount", typeof(int));
            taskReportTable.Columns.Add("TaskExceptionCount", typeof(int));
            taskReportTable.Columns.Add("TaskCompleteType", typeof(string));

            //初始化界面默认的任务参数
            textBoxPageSize.Text = taskPageSize.ToString();
            textBoxThreadNum.Text = taskThreadNum.ToString();
            textBoxExWaitTime.Text = taskExWaitTime.ToString();
            textBoxExTryNum.Text = taskExTryNum.ToString();

        }

        /// <summary>
        /// 数据库连接下拉框选择事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dbinfoSelectCombo_DbInfoSelected(object sender, DevelopTool.Forms.CommonControls.DbinfoEventArgs e)
        {
            if (e.DbInfo != null && e.IsConnect)
            {
                this.dbInfo = e.DbInfo;
                DbManagerBll dbManagerBll = new DbManagerBll(e.DbInfo);

                //获取数据库默认实例名
                string dataBaseName = dbManagerBll.GetNowUserDatabaseName();
                textBoxDataBase.Text = dataBaseName;
                taskDataBaseName = dataBaseName;
            }
            else
            {
                this.dbInfo = null;
            }
        }

        /// <summary>
        /// 获取表名集合
        /// </summary>
        /// <param name="tableNameStr"></param>
        /// <returns></returns>
        private List<string> GetTablekNameList(string tableNameStr)
        {
            var tableNames = tableNameStr.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries).ToList();
            for (int i = 0; i < tableNames.Count; i++)
            {
                tableNames[i] = tableNames[i].Replace("\r", "").Replace("\t", "").Replace("\n", "").Replace(";", "").TrimEnd().TrimStart();
            }
            return tableNames;
        }


        /// <summary>
        /// 根据表名获取任务参数
        /// </summary>
        /// <param name="tableName"></param>
        /// <returns></returns>
        private OffLineTaskParam GetTaskParam(string tableName)
        {
            string dataCompressType = Setting.Ini.Read(Setting.Section.System, Setting.Key.Data_Compress_Type, "Deflate");
            OffLineTaskParam taskParam = new OffLineTaskParam()
            {
                PageSize = taskPageSize,
                DataCompressType = dataCompressType,
                dbInfo = dbInfo,
                TableName = tableName,
                ThreadNum = taskThreadNum,
                ExceptionWaitTime = taskExWaitTime,
                ExceptionTryNum = taskExTryNum,
                Status = 0,
                DataBaseName = taskDataBaseName,
                StartTime = DateTime.Now
            };
            return taskParam;
        }

        /// <summary>
        /// 开始
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStart_Click(object sender, EventArgs e)
        {
            if (status == 0)
            {
                Start();//开始任务
            }
            else if (status == 1)
            {
                this.ShowWarningNotifier("任务已经在运行");
                return;
            }
            else if (status == 2)
            {
                //继续任务逻辑
                if (currentTaskParam.Status == 3)
                {
                    currentTaskParam.Status = 1;//只运行暂停的任务
                    btnStart.Enabled = false;
                    btnStop.Enabled = true;
                    status = 1;
                }
                else
                {
                    this.ShowWarningNotifier("当前任务的运行状态不是【暂停】");
                }

            }
            else if (status == 3)
            {
                if (this.ShowAskDialog("先前任务已取消，是否重新开始？"))
                {
                    Start();//重新开始任务
                }
            }
            else
            {
                this.ShowWarningNotifier("未知状态");
                return;
            }
        }



        private void Start()
        {
            if (this.dbinfoSelectCombo.SelectedDbInfo == null || this.dbInfo == null)
            {
                this.ShowWarningNotifier("请选择数据库连接");
                return;
            }
            if (string.IsNullOrWhiteSpace(textEditorControl.Text))
            {
                this.ShowWarningNotifier("请输入sql，每行一条");
                return;
            }
            if (textBoxThreadNum.IntValue <= 0)
            {
                this.ShowWarningNotifier("分块数量不能小于1");
                return;
            }
            if (textBoxExWaitTime.IntValue <= 0)
            {
                this.ShowWarningNotifier("超时等待不能小于1秒");
                return;
            }

            startTime = DateTime.Now;//设置开始时间
            lblStartTime.Text = startTime.DateTimeString();


            List<string> tableNameList = GetTablekNameList(textEditorControl.Text);//解析文本框的内容并获取表名集合

            if (tableNameList.Count <= 0) return;

            taskTotalNum = tableNameList.Count;//设置任务总数量
            executedNum = 0;

            batchOfflineDataBll = new BatchOfflineDataBll();//初始化批量离线操作类

            //重置
            taskReportTable.Clear();

            //创建检测任务状态的计时器
            timerCheck = new Timer
            {
                Interval = 500,
                Enabled = true
            };
            timerCheck.Tick += Timer_Tick;

            btnStart.Enabled = false;
            btnStop.Enabled = true;
            btnCancel.Enabled = true;


            backgroundWorker.RunWorkerAsync(tableNameList);//开始任务
            status = 1;
        }


        /// <summary>
        /// 计时事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void Timer_Tick(object sender, EventArgs e)
        {
            #region 总任务状态

            //总任务状态
            if (status == 0)
            {
                lblStatus.Text = "未运行";
                lblStatus.ForeColor = Color.Black;
            }
            else if (status == 1)
            {
                lblStatus.Text = "正常";
                lblStatus.ForeColor = Color.Green;
            }
            else if (status == 2)
            {
                lblStatus.Text = "暂停";
                lblStatus.ForeColor = Color.Blue;
            }
            else if (status == 3)
            {
                lblStatus.Text = "取消";
                lblStatus.ForeColor = Color.Purple;
            }
            else
            {
                lblStatus.Text = "未知";
                lblStatus.ForeColor = Color.Gray;
            }


            //总任务进度条
            var totalProgress = ((executedNum.ToDouble(1) * 100) / taskTotalNum.ToDouble(1)).ToDouble(1);
            processBarTotal.Value = Convert.ToInt32(totalProgress);
            processBarTotal.Text = totalProgress.ToString();

            lblCount.Text = executedNum + "/" + taskTotalNum;

            //总任务耗时
            TimeSpan timeSpan = new TimeSpan(startTime.Ticks).Subtract(new TimeSpan(DateTime.Now.Ticks)).Duration();
            lblTime.Text = timeSpan.TotalSeconds.ToDouble(1).ToString();

            #endregion



            #region 当前任务状态

            if (currentTaskParam != null)
            {
                textBoxTaskName.Text = currentTaskParam.TaskName;//当前任务名

                //当前任务状态
                if (currentTaskParam.Status == 0)
                {
                    lblTaskStatus.Text = "未运行";
                    lblTaskStatus.ForeColor = Color.Black;
                }
                else if (currentTaskParam.Status == 1)
                {
                    lblTaskStatus.Text = "正在运行";
                    lblTaskStatus.ForeColor = Color.Green;
                }
                else if (currentTaskParam.Status == 2)
                {
                    lblTaskStatus.Text = "已完成";
                    lblTaskStatus.ForeColor = Color.DarkGreen;
                }
                else if (currentTaskParam.Status == 3)
                {
                    lblTaskStatus.Text = "已暂停";
                    lblTaskStatus.ForeColor = Color.Blue;
                }
                else if (currentTaskParam.Status == 4)
                {
                    lblTaskStatus.Text = "手动取消";
                    lblTaskStatus.ForeColor = Color.Purple;
                }
                else if (currentTaskParam.Status == 5)
                {
                    lblTaskStatus.Text = "异常取消";
                    lblTaskStatus.ForeColor = Color.Red;
                }
                else if (currentTaskParam.Status == 6)
                {
                    lblTaskStatus.Text = "异常等待";
                    lblTaskStatus.ForeColor = Color.Orange;
                }
                else
                {
                    lblTaskStatus.Text = "未知";
                    lblTaskStatus.ForeColor = Color.Gray;
                }

                //当前任务进度条
                if (currentTaskParam.TotalRowCount > 0)
                {
                    var taskProgress = ((currentTaskParam.ExecutedRowCount.ToDouble(1) * 100) / currentTaskParam.TotalRowCount.ToDouble(1)).ToDouble(1);
                    roundProcessTask.Value = Convert.ToInt32(taskProgress);
                    roundProcessTask.Text = taskProgress.ToString() + "%";

                    //当前任务分块数
                    lblBlockCount.Text = currentTaskParam.ExecutedRowCount + "/" + currentTaskParam.TotalRowCount;
                }
                else
                {
                    roundProcessTask.Value = 0;
                    roundProcessTask.Text = 0 + "%";
                    lblBlockCount.Text = 0 + "/" + 0;
                }

                //当前任务开始时间
                lblTaskStartTime.Text = currentTaskParam.StartTime.DateTimeString();

                //当前任务耗时（秒）
                TimeSpan taskTimeSpan = new TimeSpan(currentTaskParam.StartTime.Ticks).Subtract(new TimeSpan(DateTime.Now.Ticks)).Duration();
                lblTaskTime.Text = taskTimeSpan.TotalSeconds.ToDouble(1).ToString();

                //当前任务异常尝试次数
                lblTaskExceptionCount.Text = currentTaskParam.NowExceptionTryNum.ToString();
            }
            #endregion


            if (status == 0 || status == 3)
            {
                // 停止计时器
                timerCheck.Stop();
                timerCheck.Dispose();
            }
        }



        /// <summary>
        /// 暂停
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStop_Click(object sender, EventArgs e)
        {
            status = 2;
            btnStop.Enabled = false;
            btnStart.Enabled = true;

            btnStart.Text = "继续";

            if (currentTaskParam.Status == 1)
            {
                currentTaskParam.Status = 3;//暂停当前任务
            }
        }

        /// <summary>
        /// 取消
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnCancel_Click(object sender, EventArgs e)
        {
            btnStart.Enabled = false;
            btnStop.Enabled = false;
            btnCancel.Enabled = false;

            status = 3;

            if (currentTaskParam.Status == 1 || currentTaskParam.Status == 3)
            {
                currentTaskParam.Status = 4;//取消当前任务
            }

            this.ShowWaitForm("正在取消，请稍后");
        }


        /// <summary>
        /// 启动线程
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            List<string> tableNameList = e.Argument as List<string>;

            for (int i = 0; i < tableNameList.Count; i++)
            {
                currentTaskParam = GetTaskParam(tableNameList[i]);//获取当前任务参数

                batchOfflineDataBll.Start(currentTaskParam);//开始任务

                executedNum = i + 1;//已完成任务数+1

                SetReportTableData(currentTaskParam.CloneObj());//要克隆下对象，不然状态跟不上

                backgroundWorker.ReportProgress(executedNum);//报告状态             

                if (status == 3) break;//如果已取消任务，则跳出循环
            }

            backgroundWorker.CancelAsync();//停止后台任务          
        }


        /// <summary>
        /// 设置任务报告数据
        /// </summary>
        /// <param name="offLineTaskParam"></param>
        private void SetReportTableData(OffLineTaskParam offLineTaskParam)
        {
            DataRow dataRow = taskReportTable.NewRow();
            dataRow["TaskName"] = offLineTaskParam.TaskName;
            dataRow["TaskStartTime"] = offLineTaskParam.StartTime;
            dataRow["TaskCompleteTime"] = offLineTaskParam.CompleteTime;

            if (offLineTaskParam.Status == 2)
            {
                dataRow["TaskCompleteType"] = "完成";
            }
            else if (offLineTaskParam.Status == 4)
            {
                dataRow["TaskCompleteType"] = "手动取消";
            }
            else if (offLineTaskParam.Status == 5)
            {
                dataRow["TaskCompleteType"] = "异常取消";
            }

            TimeSpan taskTimeSpan = new TimeSpan(offLineTaskParam.StartTime.Ticks).Subtract(new TimeSpan(offLineTaskParam.CompleteTime.Ticks)).Duration();
            dataRow["TaskUsageTime"] = taskTimeSpan.TotalSeconds.ToDouble(1);

            dataRow["TaskTotalRowCount"] = offLineTaskParam.TotalRowCount;
            // dataRow["TaskExceptionCount"] = offLineTaskParam.TaskExceptionCount;

            taskReportTable.Rows.Add(dataRow);
        }


        /// <summary>
        /// 线程报告进度
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {
            //绑定数据到DataGridView
            dataGridViewTaskResultList.DataSource = DataGridViewHelper.BindingSource(taskReportTable, sortStr: "TaskCompleteTime ASC");
        }

        /// <summary>
        /// 线程完成（结束）
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            if (status == 1)
                status = 0;

            this.HideWaitForm();

            btnStart.Enabled = true;
            btnStop.Enabled = false;
            btnCancel.Enabled = false;
            btnStart.Text = "开始";

            if (e.Error != null)
            {
                this.ShowErrorDialog(e.Error.Message);
                return;
            }

            if (status == 3)
            {
                this.ShowWarningNotifier("任务已取消");
            }
            else
            {
                this.ShowInfoNotifier("所有任务已完成");
            }

        }

        private void dataGridViewTaskResultList_DataSourceChanged(object sender, EventArgs e)
        {
            DataGridViewHelper.SetDataGridViewColumnInfo(dataGridViewTaskResultList, dataGridColumns);
        }

        private void dataGridViewTaskResultList_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
        {
            DataGridViewHelper.AddColumnHeader(dataGridViewTaskResultList, e);
        }


        private void textBoxPageSize_DoEnter(object sender, EventArgs e)
        {
            taskPageSize = Convert.ToInt32(textBoxPageSize.Text);
            this.ShowInfoNotifier("已应用分块数量，下个任务生效");
        }

        private void textBoxThreadNum_DoEnter(object sender, EventArgs e)
        {
            taskThreadNum = Convert.ToInt32(textBoxThreadNum.Text);
            if (currentTaskParam != null)
            {
                currentTaskParam.ThreadNum = taskThreadNum;
            }
            this.ShowInfoNotifier("已应用线程数量，即时生效");
        }

        private void textBoxExWaitTime_DoEnter(object sender, EventArgs e)
        {
            taskExWaitTime = Convert.ToInt32(textBoxExWaitTime.Text);
            if (currentTaskParam != null)
            {
                currentTaskParam.ExceptionWaitTime = taskExWaitTime;
            }
            this.ShowInfoNotifier("已应用异常等待时间，即时生效");
        }

        private void textBoxExTryNum_DoEnter(object sender, EventArgs e)
        {
            taskExTryNum = Convert.ToInt32(textBoxExTryNum.Text);
            if (currentTaskParam != null)
            {
                currentTaskParam.ExceptionTryNum = taskExTryNum;
            }
            this.ShowInfoNotifier("已应用异常尝试次数，即时生效");
        }

        private void textBoxDataBase_DoEnter(object sender, EventArgs e)
        {
            taskDataBaseName = textBoxDataBase.Text;
            if (currentTaskParam != null)
            {
                currentTaskParam.DataBaseName = taskDataBaseName;
            }
            this.ShowInfoNotifier("已应用数据库实例名，即时生效");
        }


    }
}
